package org.linlinjava.litemall.admin.aspect;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.linlinjava.litemall.db.domain.LitemallAdmin;
import org.linlinjava.litemall.db.domain.LitemallAdminExample;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

@Aspect
@Component
public class VendorAspect {
    private final Log logger = LogFactory.getLog(VendorAspect.class);

    // 定义切点Pointcut
    @Pointcut("execution(public * org.linlinjava.litemall.db.dao.*.*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

        try {
            Subject currentUser = SecurityUtils.getSubject();
            LitemallAdmin admin = (LitemallAdmin) currentUser.getPrincipal();

            if(null != admin) {
                for (Object arg : pjp.getArgs()) {
                    MetaObject mo = SystemMetaObject.forObject(arg);
                    //*Example
                    if (mo.hasGetter("oredCriteria")) {

                        List<Object> list = (List<Object>) mo.getValue("oredCriteria");
                        if (null != list) {
                            for (Object criteria : list) {
                                Field criterionField = ReflectionUtils.findField(criteria.getClass(), "criteria");
                                if (null == criterionField) {
                                    continue;
                                }

                                criterionField.setAccessible(true);
                                List criterionList = (List) ReflectionUtils.getField(criterionField, criteria);

                                if (null != criterionList) {
                                    //是否已经设置了vendor_id筛选条件
                                    boolean found = isVendorIdConditionSet(criterionList);

                                    //没有设置vendor_id筛选条件的且没有配置ThreadLocal标志位的
                                    // 才添加vendor_id = 条件
                                    Boolean tagSet = IgnoreVendorIdConditionAspect.isIgnoreVendorIdCondition.get();
                                    if (!found && (null == tagSet || !tagSet)) {
                                        //AdminDAO的不加vendorId条件，一堆问题
                                        if(criteria.getClass() != LitemallAdminExample.Criteria.class) {
                                            try {
                                                Method vendorMethod = criteria.getClass().getDeclaredMethod("andVendorIdEqualTo", Long.class);
                                                vendorMethod.invoke(criteria, admin.getVendorId());
                                            } catch (NoSuchMethodException e) {
                                                logger.trace(e.getMessage());
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // Domain
                    else if (mo.hasGetter("vendorId")) {
                        if (null == mo.getValue("vendorId")) {
                            mo.setValue("vendorId", admin.getVendorId());
                        }
                    }
                }
            }
        } catch (UnavailableSecurityManagerException e) {
            logger.trace("SecurityManager尚未初始化");
        }

        Object result = pjp.proceed();
        return result;
    }

    private boolean isVendorIdConditionSet(List criterionList) throws IllegalAccessException {
        boolean found = false;
        for (Object criterion : criterionList) {
            Field field = ReflectionUtils.findField(criterion.getClass(), "condition");
            if (null != field) {
                field.setAccessible(true);
                Object condition = field.get(criterion);
                if (condition instanceof String && ((String) condition).contains("vendor_id")) {
                    found = true;
                    break;
                }
            }
        }
        return found;
    }
}